home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / stdwin / Ports / mac / scroll.c < prev    next >
Text File  |  1995-12-21  |  15KB  |  655 lines

  1. /*
  2. This code is somehow broken.
  3. If I click a few times on an arrow of the scroll bar the cursor freezes.
  4. Other forms of scrolling don't have this problem.  WHAT'S WRONG?!?!?!
  5. */
  6.  
  7. /* MAC STDWIN -- SCROLLING. */
  8.  
  9. /* All non-public functions here assume the current grafport is set */
  10.  
  11. /* XXX The contents of this file should be organized more top-down */
  12.  
  13. #include "macwin.h"
  14.  
  15. #ifndef HAVE_UNIVERSAL_HEADERS
  16. #define ControlActionUPP ProcPtr
  17. #define NewControlActionProc(x) ((ProcPtr)x)
  18. #endif
  19.  
  20. /* I am using the fact here that the scroll bars of an inactive window
  21.    are invisible:
  22.    when a window's origin or its document size changes while it isn't the
  23.    active window, its controls get their new values but aren't redrawn. */
  24.  
  25. /* Key repeat constants in low memory (set by the Control Panel),
  26.    in ticks (used here to control the continuous scrolling speed). */
  27.  
  28. #define KeyThresh    (* (short*)0x18e)    /* Delay until repeat starts */
  29. #define KeyRepThresh    (* (short*)0x190)    /* Repeat rate */
  30.  
  31. STATIC void setscrollbarvalues _ARGS((WINDOW *win));
  32. STATIC void usescrollbarvalues _ARGS((WINDOW *win));
  33. STATIC void sizescrollbars _ARGS((WINDOW *win));
  34. STATIC int calcneworigin _ARGS((int, int, int, int, int));
  35. STATIC void calcbar _ARGS((ControlHandle bar,
  36.     int org, int size, int begin, int end));
  37. STATIC void setbar _ARGS((ControlHandle bar, int winsize, int val, int max));
  38. STATIC void deltabar _ARGS((ControlHandle bar, int delta));
  39. STATIC void showbar _ARGS((ControlHandle bar));
  40. STATIC void hidebar _ARGS((ControlHandle bar));
  41. STATIC void movebar _ARGS((ControlHandle bar,
  42.     int left, int top, int right, int bottom));
  43. void _wfixorigin _ARGS((WINDOW *));
  44.  
  45. void
  46. wsetorigin(win, orgh, orgv)
  47.     WINDOW *win;
  48.     int orgh, orgv;
  49. {
  50.     Rect r;
  51.     
  52.     /* XXX wsetorigin is currently the only routine that allows
  53.        the application to show bits outside the document.
  54.        Is even this desirable? */
  55.     
  56.     CLIPMIN(orgh, 0);
  57.     CLIPMIN(orgv, 0);
  58.     getwinrect(win, &r);
  59.     orgh -= LSLOP;
  60.     if (orgh != win->orgh || orgv != win->orgv) {
  61.         SetPort(win->w);
  62.         scrollby(win, &r, win->orgh - orgh, win->orgv - orgv);
  63.         win->orgh= orgh;
  64.         win->orgv= orgv;
  65.         setscrollbarvalues(win);
  66.     }
  67. }
  68.  
  69. void
  70. wgetorigin(win, ph, pv)
  71.     WINDOW *win;
  72.     int *ph, *pv;
  73. {
  74.     *ph = win->orgh + LSLOP;
  75.     *pv = win->orgv;
  76. }
  77.  
  78. void
  79. wshow(win, left, top, right, bottom)
  80.     WINDOW *win;
  81.     int left, top, right, bottom;
  82. {
  83.     int orgh, orgv;
  84.     int winwidth, winheight;
  85.     int docwidth, docheight;
  86.     
  87.     /* Calls to wshow while the mouse is down are ignored,
  88.        because they tend to mess up auto-scrolling.
  89.        I presume it's harmless (even the right thing to do),
  90.        since wshow is usually called to make sure the object
  91.        being selected is visible, which isn't a problem while
  92.        the user is busy pointing at it.
  93.        The check must be here, not in wsetorigin, because
  94.        the latter is used internally by the auto-scroll code! */
  95.     if (_wm_down)
  96.         return;
  97.     
  98.     /* The code below is generic for all versions of stdwin */
  99.     
  100.     wgetorigin(win, &orgh, &orgv);
  101.     wgetwinsize(win, &winwidth, &winheight);
  102.     wgetdocsize(win, &docwidth, &docheight);
  103.     
  104.     orgh = calcneworigin(orgh, left, right, winwidth, docwidth);
  105.     orgv = calcneworigin(orgv, top, bottom, winheight, docheight);
  106.     
  107.     wsetorigin(win, orgh, orgv);
  108. }
  109.  
  110. /* Subroutine for wshow to calculate new origin in h or v direction */
  111.  
  112. static int
  113. calcneworigin(org, low, high, winsize, docsize)
  114.     int org, low, high, winsize, docsize;
  115. {
  116.     if (docsize <= 0)
  117.         return org;
  118.     
  119.     /* Ignore requests to show bits outside doc */
  120.     /* XXX Is this necessary? */
  121.     CLIPMIN(low, 0);
  122.     CLIPMAX(high, docsize);
  123.     
  124.     /* Ignore requests for empty range */
  125.     /* XXX Is this what we want? */
  126.     if (high <= low)
  127.         return org;
  128.     
  129.     if (org <= low && high <= org + winsize)
  130.         return org;
  131.     
  132.     if (high - low > winsize) {    /* Range too big for window */
  133.         
  134.         /* Don't scroll if at least 1/3 of the window is in range */
  135.         /* XXX 1/3 is an arbitrary number! */
  136.         if (low <= org + winsize*2/3 && high >= org + winsize/3)
  137.             return org;
  138.         
  139.         /* Center the end of the range that's closest to the window */
  140.         if (low - org >= org + winsize - high) {
  141.             org = low - winsize/2;
  142.             CLIPMIN(org, 0);
  143.             return org;
  144.         }
  145.         else {
  146.             org = high - winsize/2;
  147.             CLIPMAX(org, docsize);
  148.             CLIPMIN(org, 0);
  149.             return org;
  150.         }
  151.     }
  152.     
  153.     /* The whole range will fit */
  154.     
  155.     /* See if it makes sense to scroll less than the window size */
  156.     if (low < org) {
  157.         if (org - low < winsize)
  158.             return low;
  159.     }
  160.     else if (high > org + winsize) {
  161.         if (high - (org + winsize) < winsize)
  162.             return high - winsize;
  163.     }
  164.     
  165.     /* Would have to scroll at least winsize -- center the range */
  166.     org = (low + high - winsize) / 2;
  167.     
  168.     /* Make sure we stay within the document */
  169.     CLIPMIN(org, 0);
  170.     CLIPMAX(org, docsize);
  171.     
  172.     return org;
  173. }
  174.  
  175. void
  176. wsetdocsize(win, docwidth, docheight)
  177.     WINDOW *win;
  178.     int docwidth, docheight;
  179. {
  180.     CLIPMIN(docwidth, 0);
  181.     CLIPMIN(docheight, 0);
  182.     if (docwidth == win->docwidth && docheight == win->docheight)
  183.         return;
  184.     win->docwidth= docwidth;
  185.     win->docheight= docheight;
  186.     SetPort(win->w);
  187.     setscrollbarvalues(win);
  188.     _wfixorigin(win);
  189.     
  190.     /* Make the zoomed window size the full document size,
  191.        or the full screen size if the document is bigger. */
  192.     
  193.     if (((WindowPeek)(win->w))->dataHandle != NULL) {
  194.         WStateData *data = (WStateData *)
  195.             *((WindowPeek)(win->w))->dataHandle;
  196.         if (data != NULL) {
  197.             if (docwidth > 0) {
  198.                 data->stdState.right =
  199.                     data->stdState.left
  200.                     + LSLOP + docwidth + RSLOP;
  201.                 if (win->vbar != NULL)
  202.                     data->stdState.right += BAR;
  203.             }
  204.             else
  205.                 data->stdState.right = 0x7fff;
  206.             CLIPMAX(data->stdState.right,
  207.                 screen->portRect.right-3);
  208.             if (win->hbar != NULL) {
  209.                 CLIPMIN(data->stdState.right, 5*BAR);
  210.             }
  211.             if (docheight > 0) {
  212.                 data->stdState.bottom =
  213.                     data->stdState.top + docheight;
  214.                 if (win->hbar != NULL)
  215.                     data->stdState.bottom += BAR;
  216.             }
  217.             else
  218.                 data->stdState.bottom = 0x7fff;
  219.             CLIPMAX(data->stdState.bottom,
  220.                 screen->portRect.bottom-3);
  221.             if (win->vbar != NULL) {
  222.                 CLIPMIN(data->stdState.bottom, 5*BAR);
  223.             }
  224.         }
  225.     }
  226. }
  227.  
  228. void
  229. wgetdocsize(win, pwidth, pheight)
  230.     WINDOW *win;
  231.     int *pwidth, *pheight;
  232. {
  233.     *pwidth = win->docwidth;
  234.     *pheight = win->docheight;
  235. }
  236.  
  237. /* Fix the window's origin after a document or window resize.
  238.    (Also used from do_size() in event.c) */
  239.  
  240. void
  241. _wfixorigin(win)
  242.     WINDOW *win;
  243. {
  244.     int orgh, orgv;
  245.     int winwidth, winheight;
  246.     int docwidth, docheight;
  247.     wgetorigin(win, &orgh, &orgv);
  248.     wgetwinsize(win, &winwidth, &winheight);
  249.     wgetdocsize(win, &docwidth, &docheight);
  250.     
  251.     /* XXX Do we really want this?
  252.        This means that in a text edit window, if you are focused
  253.        at the bottom, every line deletion causes a scroll.
  254.        Oh well, I suppose that text edit windows could fix
  255.        their document size to include some blank lines at the
  256.        end...
  257.     */
  258.     
  259.     CLIPMAX(orgh, docwidth - winwidth);
  260.     CLIPMIN(orgh, 0);
  261.     CLIPMAX(orgv, docheight - winheight);
  262.     CLIPMIN(orgv, 0);
  263.     wsetorigin(win, orgh, orgv);
  264. }
  265.  
  266. /* do_scroll is called from event.c when a click in a scroll bar
  267.    is detected */
  268.  
  269. STATIC pascal trackbar(ControlHandle bar, short pcode); /* Forward */
  270.  
  271. static WINDOW *scrollwin;    /* The window (needed by 'trackbar') */
  272. static int scrollstep;        /* By how much we scroll */
  273. static long deadline;        /* When the next step may happen */
  274.  
  275. void
  276. do_scroll(pwhere, win, bar, pcode)
  277.     Point *pwhere;
  278.     WINDOW *win;
  279.     ControlHandle bar;
  280.     int pcode;
  281. {
  282.     int step, page;
  283.     ControlActionUPP action;
  284.     int width, height;
  285.     
  286.     if (bar == NULL)
  287.         return;
  288.     
  289.     wgetwinsize(win, &width, &height);
  290.     
  291.     if (bar == win->hbar) {
  292.         step= width / 20;
  293.         CLIPMIN(step, 1);
  294.         page= width / 2;
  295.     }
  296.     else if (bar == win->vbar) {
  297.         step= wlineheight(); /* Should use current win's */
  298.         page= height - step;
  299.     }
  300.     else
  301.         return;
  302.     
  303.     page= (page/step) * step; /* Round down to multiple of step */
  304.     action = NewControlActionProc(trackbar);
  305.     scrollwin= win;
  306.     
  307.     switch (pcode) {
  308.     case inUpButton:
  309.         scrollstep= -step;
  310.         break;
  311.     case inDownButton:
  312.         scrollstep= step;
  313.         break;
  314.     case inPageUp:
  315.         scrollstep= -page;
  316.         break;
  317.     case inPageDown:
  318.         scrollstep= page;
  319.         break;
  320.     default:
  321.         action= NULL;
  322.         break;
  323.     }
  324.     
  325.     deadline= 0;
  326.     if (TrackControl(bar, PASSPOINT *pwhere, action) == inThumb)
  327.         usescrollbarvalues(win);
  328.     
  329.     SetPort(win->w); /*  THIS IS NEEDED!!! */
  330. }
  331.  
  332. /* Use new-style prototype for __MWERKS__ */
  333. STATIC pascal trackbar(ControlHandle bar, short pcode)
  334. {
  335.     long now= TickCount();
  336.     if (now >= deadline && pcode != 0) {
  337.          deltabar(bar, scrollstep);
  338.         usescrollbarvalues(scrollwin);
  339.         wupdate(scrollwin);
  340.         if (deadline == 0 && KeyThresh > KeyRepThresh)
  341.             deadline= now + KeyThresh;
  342.             /* Longer delay first time */
  343.         else
  344.             deadline= now + KeyRepThresh;
  345.     }
  346. }
  347.  
  348. /* Automatic scrolling when the mouse is pressed and moved outside
  349.    the application panel. */
  350.  
  351. void
  352. autoscroll(win, h, v)
  353.     WINDOW *win;
  354.     int h, v; /* Mouse location in local coordinates */
  355. {
  356.     Rect r;
  357.     int dh= 0, dv= 0;
  358.     
  359.     getwinrect(win, &r);
  360.     if (h < r.left)
  361.         dh= h - r.left;
  362.     else if (h > r.right)
  363.         dh= h - r.right;
  364.     if (v < r.top)
  365.         dv= v - r.top;
  366.     else if (v > r.bottom)
  367.         dv= v - r.bottom;
  368.     if (dh != 0 || dv != 0) {
  369.         /* NOTE: assuming current grafport is win->w */
  370.         deltabar(win->hbar, dh);
  371.         deltabar(win->vbar, dv);
  372.         usescrollbarvalues(win);
  373.     }
  374. }
  375.  
  376. /* Alternative scrolling: Option-click produces a 'hand' cursor
  377.    and allows scrolling like in MacPaint.  Called from event.c. */
  378.  
  379. void
  380. dragscroll(win, h, v, constrained)
  381.     WINDOW *win;
  382.     int h, v;
  383.     int constrained;
  384. {
  385.     int do_h= !constrained, do_v= !constrained;
  386.     
  387.     while (StillDown()) {
  388.         Point mouse;
  389.         SetPort(win->w);
  390.         GetMouse(&mouse);
  391.         if (constrained) {
  392.             int ah= ABS(h - mouse.h);
  393.             int av= ABS(v - mouse.v);
  394.             if (ABS(ah - av) < 2)
  395.                 continue;
  396.             if (ah > av)
  397.                 do_h= TRUE;
  398.             else
  399.                 do_v= TRUE;
  400.             constrained= FALSE;
  401.         }
  402.         if (do_h)
  403.             deltabar(win->hbar, h - mouse.h);
  404.         if (do_v)
  405.             deltabar(win->vbar, v - mouse.v);
  406.         usescrollbarvalues(win);
  407.         wupdate(win);
  408.         h= mouse.h;
  409.         v= mouse.v;
  410.     }
  411. }
  412.  
  413. void
  414. makescrollbars(win, hor, ver)
  415.     WINDOW *win;
  416.     /*bool*/int hor, ver;
  417. {
  418.     Rect r;
  419.     
  420.     /* The scroll bars are initially created at a dummy location,
  421.        and then moved to their proper location.
  422.        They are not displayed here;
  423.        that's done only when an activate event arrives. */
  424.     SetRect(&r, 0, 0, 1, 1); /* Dummy rectangle */
  425.     if (hor)
  426.         win->hbar= NewControl(win->w,
  427.             &r, (ConstStr255Param)"", false, 0, 0, 0, scrollBarProc, 0L);
  428.     if (ver)
  429.         win->vbar= NewControl(win->w,
  430.             &r, (ConstStr255Param)"", false, 0, 0, 0, scrollBarProc, 0L);
  431.     sizescrollbars(win);
  432. }
  433.  
  434. void
  435. showscrollbars(win)
  436.     WINDOW *win;
  437. {
  438.     _wgrowicon(win);
  439.     showbar(win->hbar);
  440.     showbar(win->vbar);
  441. }
  442.  
  443. void
  444. hidescrollbars(win)
  445.     WINDOW *win;
  446. {
  447.     hidebar(win->hbar);
  448.     hidebar(win->vbar);
  449. }
  450.  
  451. void
  452. movescrollbars(win)
  453.     WINDOW *win;
  454. {
  455.     hidescrollbars(win);
  456.     sizescrollbars(win);
  457.     showscrollbars(win);
  458. }
  459.  
  460. static void
  461. sizescrollbars(win)
  462.     WINDOW *win;
  463. {
  464.     Rect r;
  465.     
  466.     /* This must only be called while the scroll bars are invisible. */
  467.     
  468.     r = win->w->portRect;
  469.     r.left = r.right - BAR;
  470.     r.top--;
  471.     r.bottom -= BAR-1;
  472.     r.right++;
  473.     movebar(win->vbar, r.left, r.top, r.right, r.bottom);
  474.     
  475.     r = win->w->portRect;
  476.     r.left--;
  477.     r.top = r.bottom - BAR;
  478.     r.right -= BAR-1;
  479.     r.bottom++;
  480.     movebar(win->hbar, r.left, r.top, r.right, r.bottom);
  481.     
  482.     setscrollbarvalues(win);
  483. }
  484.  
  485. static void
  486. setscrollbarvalues(win)
  487.     WINDOW *win;
  488. {
  489.     Rect r;
  490.     
  491.     getwinrect(win, &r);
  492.     calcbar(win->hbar,
  493.         win->orgh, win->docwidth, LSLOP, r.right - r.left - RSLOP);
  494.     calcbar(win->vbar,
  495.         win->orgv, win->docheight, 0, r.bottom - r.top);
  496.     if (win == active) {
  497.         /* XXX Should only draw those controls that have changed. */
  498.         DrawControls(win->w);
  499.         valid_border(win->w);
  500.     }
  501. }
  502.  
  503. /*
  504.  * Calculate (and set!) the new value of a scroll bar.
  505.  * Parameters (all pertaining to either h or v): 
  506.  * org:     origin of window (win->orgh or win->orgv)
  507.  * size:    extent of document (win->docwidth or win->docheight)
  508.  * begin:    position of document origin if bar is at its beginning
  509.  * end:        position of document end if bar is at its end
  510.  * Situation sketch:
  511.  *                0    begin                          end  winwidth
  512.  *                +====+==============================+====+
  513.  *                     +--------------------------------------------------+
  514.  * +--------------------------------------------------+
  515.  * Window shown on top; min document position in the middle;
  516.  * max document position below.  Org is (begin of win) - (begin of doc).
  517.  */
  518.  
  519. static void
  520. calcbar(bar, org, size, begin, end)
  521.     ControlHandle bar;
  522.     int org, size;
  523.     int begin, end;
  524. {
  525.     int range;
  526.     
  527.     if (bar == NULL)
  528.         return;
  529.     
  530.     /* For the caller it's easier to remember to pass win->org{h,v};
  531.        but for our calculations it's easier to have the sign reversed! */
  532.     org= -org;
  533.     CLIPMIN(begin, org);
  534.     CLIPMIN(size, 0);
  535.     CLIPMAX(end, org + size);
  536.     range = size - (end - begin);
  537.     CLIPMIN(range, 0);
  538.     setbar(bar, end - begin, begin - org, range);
  539. }
  540.  
  541. static void
  542. usescrollbarvalues(win)
  543.     WINDOW *win;
  544. {
  545.     int orgh = 0;
  546.     int orgv = 0;
  547.     if (win->hbar != NULL)
  548.         orgh = GetCtlValue(win->hbar) - GetCtlMin(win->hbar);
  549.     if (win->vbar != NULL)
  550.         orgv = GetCtlValue(win->vbar) - GetCtlMin(win->vbar);
  551.     wsetorigin(win, orgh, orgv);
  552.     /* Implies setscrollbarvalues! */
  553. }
  554.  
  555. static void
  556. setbar(bar, winsize, val, max)
  557.     ControlHandle bar;
  558.     int winsize, val, max;
  559. {
  560.     if (bar != NULL) {
  561.         ControlPtr p= *bar;
  562.         if (max < 0)
  563.             max= 0;
  564.         if (val > max)
  565.             val= max;
  566.         if (val < 0)
  567.             val= 0;
  568.         p->contrlMin= winsize;
  569.         p->contrlValue= val + winsize;
  570.         p->contrlMax= max + winsize;
  571.         /* Must be drawn by DrawControls or ShowControl. */
  572.     }
  573. }
  574.  
  575. static void
  576. deltabar(bar, delta)
  577.     ControlHandle bar;
  578.     int delta;
  579. {
  580.     int min, val, max, newval;
  581.     
  582.     if (bar == NULL)
  583.         return;
  584.     min = GetCtlMin(bar);
  585.     val = GetCtlValue(bar);
  586.     max = GetCtlMax(bar);
  587.     newval = val + delta;
  588.     
  589.     if (newval > max)
  590.         newval= max;
  591.     if (newval < min)
  592.         newval= min;
  593.     if (newval != val)
  594.         SetCtlValue(bar, newval);
  595. }
  596.  
  597. static void
  598. showbar(bar)
  599.     ControlHandle bar;
  600. {
  601.     if (bar != NULL)
  602.         ShowControl(bar);
  603. }
  604.  
  605. static void
  606. hidebar(bar)
  607.     ControlHandle bar;
  608. {
  609.     if (bar != NULL)
  610.         HideControl(bar);
  611. }
  612.  
  613. static void
  614. movebar(bar, left, top, right, bottom)
  615.     ControlHandle bar;
  616.     int left, top, right, bottom;
  617. {
  618.     if (bar != NULL) {
  619.         /* This works best while the scroll bar is invisible. */
  620.         MoveControl(bar, left, top);
  621.         SizeControl(bar, right-left, bottom-top);
  622.     }
  623. }
  624.  
  625. void
  626. _wgrowicon(win)
  627.     WINDOW *win;
  628. {
  629.     Rect r;
  630.     
  631.     /* If there are no scroll bars, there is no room to draw the
  632.        grow icon; the entire window belongs to the application.
  633.        However, clicks in the bottom right corner will still be
  634.        intercepted by the window manager. */
  635.     
  636.     if (win->hbar == NULL && win->vbar == NULL)
  637.         return;
  638.     
  639.     /* Clip the drawing of DrawGrowIcon to the scroll bars present. */
  640.     
  641.     r= win->w->portRect;
  642.     if (win->hbar == NULL)
  643.         r.left = r.right - BAR;
  644.     if (win->vbar == NULL)
  645.         r.top = r.bottom - BAR;
  646.     ClipRect(&r);
  647.     
  648.     DrawGrowIcon(win->w);
  649.     
  650.     /* Reset clipping */
  651.     
  652.     SetRect(&r, -32000, -32000, 32000, 32000);
  653.     ClipRect(&r);
  654. }
  655.